import makeStyles from '@mui/styles/makeStyles';
import { graphql } from 'react-relay';
import * as Yup from 'yup';
import React, { FunctionComponent } from 'react';
import { FormikConfig } from 'formik/dist/types';
import { Field, Form, Formik } from 'formik';
import Button from '@mui/material/Button';
import { RecordSourceSelectorProxy } from 'relay-runtime';
import Drawer, { DrawerControlledDialProps, DrawerVariant } from '@components/common/drawer/Drawer';
import useHelper from 'src/utils/hooks/useHelper';
import ObjectAssigneeField from '@components/common/form/ObjectAssigneeField';
import { MalwareAnalysesLinesPaginationQuery$variables } from '@components/analyses/__generated__/MalwareAnalysesLinesPaginationQuery.graphql';
import { useFormatter } from '../../../../components/i18n';
import { insertNode } from '../../../../utils/store';
import TextField from '../../../../components/TextField';
import CreatedByField from '../../common/form/CreatedByField';
import ObjectMarkingField from '../../common/form/ObjectMarkingField';
import type { Theme } from '../../../../components/Theme';
import {
  MalwareAnalysisCreationMutation,
  MalwareAnalysisCreationMutation$variables as MalwareAnalysisMutationVariables,
} from './__generated__/MalwareAnalysisCreationMutation.graphql';
import DateTimePickerField from '../../../../components/DateTimePickerField';
import ObjectLabelField from '../../common/form/ObjectLabelField';
import OpenVocabField from '../../common/form/OpenVocabField';
import { fieldSpacingContainerStyle } from '../../../../utils/field';
import { ExternalReferencesField } from '../../common/form/ExternalReferencesField';
import ConfidenceField from '../../common/form/ConfidenceField';
import { useSchemaCreationValidation } from '../../../../utils/hooks/useEntitySettings';
import { Option } from '../../common/form/ReferenceField';
import { handleErrorInForm } from '../../../../relay/environment';
import useDefaultValues from '../../../../utils/hooks/useDefaultValues';
import CustomFileUploader from '../../common/files/CustomFileUploader';
import useApiMutation from '../../../../utils/hooks/useApiMutation';
import CreateEntityControlledDial from '../../../../components/CreateEntityControlledDial';

// Deprecated - https://mui.com/system/styles/basics/
// Do not use it for new code.
const useStyles = makeStyles<Theme>((theme) => ({
  buttons: {
    marginTop: 20,
    textAlign: 'right',
  },
  button: {
    marginLeft: theme.spacing(2),
  },
}));

const malwareAnalysisMutation = graphql`
  mutation MalwareAnalysisCreationMutation($input: MalwareAnalysisAddInput!) {
    malwareAnalysisAdd(input: $input) {
      ...MalwareAnalysesLine_node
    }
  }
`;

interface MalwareAnalysisAddInput {
  product: string;
  result_name: string;
  version: string;
  createdBy?: Option;
  objectLabel: Option[];
  objectAssignee: { value: string }[];
  submitted: Date | null;
  result: string;
  objectMarking: Option[];
  externalReferences: { value: string }[];
  confidence: number | undefined;
  file: File | undefined;
  configuration_version: string | null;
  analysis_started: Date | null;
  analysis_ended: Date | null;
  analysis_engine_version: string | null;
  analysis_definition_version: string | null;
  modules: string | undefined;
}

interface MalwareAnalysisFormProps {
  updater: (store: RecordSourceSelectorProxy, key: string) => void;
  onClose?: () => void;
  inputValue?: string;
  defaultCreatedBy?: Option;
  defaultMarkingDefinitions?: Option[];
  defaultConfidence?: number;
}

const MALWARE_ANALYSIS_TYPE = 'Malware-Analysis';

export const MalwareAnalysisCreationForm: FunctionComponent<
MalwareAnalysisFormProps
> = ({
  updater,
  onClose,
  inputValue,
  defaultConfidence,
  defaultCreatedBy,
  defaultMarkingDefinitions,
}) => {
  const classes = useStyles();
  const { t_i18n } = useFormatter();
  const basicShape = {
    result_name: Yup.string().required(t_i18n('This field is required')),
    product: Yup.string().required(t_i18n('This field is required')),
    submitted: Yup.date().nullable()
      .typeError(t_i18n('The value must be a datetime (yyyy-MM-dd hh:mm (a|p)m)')),
    confidence: Yup.number(),
    configuration_version: Yup.string().nullable(),
    analysis_started: Yup.date().nullable()
      .typeError(t_i18n('The value must be a datetime (yyyy-MM-dd hh:mm (a|p)m)')),
    analysis_ended: Yup.date().nullable()
      .typeError(t_i18n('The value must be a datetime (yyyy-MM-dd hh:mm (a|p)m)')),
    analysis_engine_version: Yup.string().nullable(),
    analysis_definition_version: Yup.string().nullable(),
    modules: Yup.string().nullable(),
  };
  const malwareAnalysisValidator = useSchemaCreationValidation(
    MALWARE_ANALYSIS_TYPE,
    basicShape,
  );
  const [commit] = useApiMutation<MalwareAnalysisCreationMutation>(
    malwareAnalysisMutation,
    undefined,
    { successMessage: `${t_i18n('entity_Malware-Analysis')} ${t_i18n('successfully created')}` },
  );
  const onSubmit: FormikConfig<MalwareAnalysisAddInput>['onSubmit'] = (
    values,
    { setSubmitting, resetForm, setErrors },
  ) => {
    const finalValues: MalwareAnalysisMutationVariables['input'] = {
      result_name: values.result_name,
      product: values.product,
      version: values.version,
      createdBy: values.createdBy?.value,
      objectLabel: values.objectLabel.map((v) => v.value),
      objectAssignee: values.objectAssignee.map(({ value }) => value),
      submitted: values.submitted,
      result: values.result,
      objectMarking: values.objectMarking.map(({ value }) => value),
      externalReferences: values.externalReferences.map(({ value }) => value),
      confidence: parseInt(String(values.confidence), 10),
      file: values.file,
      configuration_version: values.configuration_version,
      analysis_started: values.analysis_started,
      analysis_ended: values.analysis_ended,
      analysis_engine_version: values.analysis_engine_version,
      analysis_definition_version: values.analysis_definition_version,
      modules: values.modules?.split('\n') ?? [],
    };
    commit({
      variables: {
        input: finalValues,
      },
      updater: (store) => {
        if (updater) {
          updater(store, 'malwareAnalysisAdd');
        }
      },
      onError: (error: Error) => {
        handleErrorInForm(error, setErrors);
        setSubmitting(false);
      },
      onCompleted: () => {
        setSubmitting(false);
        resetForm();
        if (onClose) {
          onClose();
        }
      },
    });
  };

  const initialValues = useDefaultValues<MalwareAnalysisAddInput>(
    MALWARE_ANALYSIS_TYPE,
    {
      result_name: inputValue ?? '',
      product: '',
      version: '',
      createdBy: defaultCreatedBy,
      objectLabel: [],
      objectAssignee: [],
      submitted: null,
      result: '',
      objectMarking: defaultMarkingDefinitions ?? [],
      externalReferences: [],
      confidence: defaultConfidence,
      file: undefined,
      configuration_version: '',
      analysis_started: null,
      analysis_ended: null,
      analysis_engine_version: '',
      analysis_definition_version: '',
      modules: '',
    },
  );

  return (
    <Formik<MalwareAnalysisAddInput>
      initialValues={initialValues}
      validationSchema={malwareAnalysisValidator}
      onSubmit={onSubmit}
      onReset={onClose}
    >
      {({ submitForm, handleReset, isSubmitting, setFieldValue, values }) => (
        <Form style={{ margin: '20px 0 20px 0' }}>
          <Field
            component={TextField}
            name="product"
            label={t_i18n('Product')}
            fullWidth={true}
          />
          <Field
            component={TextField}
            name="result_name"
            label={t_i18n('Report name')}
            fullWidth={true}
            style={{ marginTop: 20 }}
          />
          <Field
            component={TextField}
            name="version"
            label={t_i18n('Version of the product')}
            fullWidth={true}
            style={{ marginTop: 20 }}
          />
          <Field
            component={DateTimePickerField}
            name="submitted"
            textFieldProps={{
              label: t_i18n('Submission date'),
              fullWidth: true,
              style: { marginTop: 20 },
            }}
          />
          <OpenVocabField
            label={t_i18n('Maliciousness')}
            type="malware-result-ov"
            name="result"
            onChange={setFieldValue}
            multiple={false}
            containerStyle={fieldSpacingContainerStyle}
          />
          <ConfidenceField
            containerStyle={fieldSpacingContainerStyle}
            entityType="Malware-Analysis"
          />
          <ObjectAssigneeField
            name="objectAssignee"
            style={fieldSpacingContainerStyle}
          />
          <CreatedByField
            name="createdBy"
            style={{ marginTop: 20, width: '100%' }}
            setFieldValue={setFieldValue}
          />
          <ObjectLabelField
            name="objectLabel"
            style={{ marginTop: 20 }}
            setFieldValue={setFieldValue}
            values={values.objectLabel}
          />
          <ObjectMarkingField
            name="objectMarking"
            style={{ marginTop: 20, width: '100%' }}
            setFieldValue={setFieldValue}
          />
          <ExternalReferencesField
            name="externalReferences"
            style={{ marginTop: 20, width: '100%' }}
            setFieldValue={setFieldValue}
            values={values.externalReferences}
          />
          <CustomFileUploader setFieldValue={setFieldValue} />
          <Field
            component={TextField}
            name="configuration_version"
            label={t_i18n('Configuration version')}
            fullWidth
            style={{ marginTop: 20 }}
          />
          <Field
            component={DateTimePickerField}
            name="analysis_started"
            textFieldProps={{
              label: t_i18n('Analysis started'),
              fullWidth: true,
              style: { marginTop: 20 },
            }}
          />
          <Field
            component={DateTimePickerField}
            name="analysis_ended"
            textFieldProps={{
              label: t_i18n('Analysis ended'),
              fullWidth: true,
              style: { marginTop: 20 },
            }}
          />
          <Field
            component={TextField}
            name="analysis_engine_version"
            label={t_i18n('Analysis engine version')}
            fullWidth
            style={{ marginTop: 20 }}
          />
          <Field
            component={TextField}
            name="analysis_definition_version"
            label={t_i18n('Analysis definition version')}
            fullWidth
            style={{ marginTop: 20 }}
          />
          <Field
            component={TextField}
            name="modules"
            label={t_i18n('Modules (1 / line)')}
            fullWidth
            multiline
            rows="4"
            style={{ marginTop: 20 }}
          />
          <div className={classes.buttons}>
            <Button
              variant="contained"
              onClick={handleReset}
              disabled={isSubmitting}
              classes={{ root: classes.button }}
            >
              {t_i18n('Cancel')}
            </Button>
            <Button
              variant="contained"
              color="secondary"
              onClick={submitForm}
              disabled={isSubmitting}
              classes={{ root: classes.button }}
            >
              {t_i18n('Create')}
            </Button>
          </div>
        </Form>
      )}
    </Formik>
  );
};

const MalwareAnalysisCreation = ({
  paginationOptions,
}: {
  paginationOptions: MalwareAnalysesLinesPaginationQuery$variables;
}) => {
  const { t_i18n } = useFormatter();
  const { isFeatureEnable } = useHelper();
  const isFABReplaced = isFeatureEnable('FAB_REPLACEMENT');
  const updater = (store: RecordSourceSelectorProxy) => insertNode(
    store,
    'Pagination_malwareAnalyses',
    paginationOptions,
    'malwareAnalysisAdd',
  );
  const CreateMalwareAnalysisControlledDial = (props: DrawerControlledDialProps) => (
    <CreateEntityControlledDial entityType='Malware-Analysis' {...props} />
  );
  const renderClassic = () => (
    <Drawer
      title={t_i18n('Create a malware analysis')}
      variant={isFABReplaced ? undefined : DrawerVariant.create}
      controlledDial={isFABReplaced ? CreateMalwareAnalysisControlledDial : undefined}
    >
      <MalwareAnalysisCreationForm updater={updater} />
    </Drawer>
  );
  return renderClassic();
};

export default MalwareAnalysisCreation;
